<template>
  <div class="canvas-one">
    <h1>第一层：下面都是一些数据可视化实例。</h1>
    <div class="canvas-clock">
      <h1>第二层：时钟</h1>
      <canvas id="clockCanvas" width="400" height="400"></canvas>
    </div>
    <div class="canvas-histogram">
      <h1>第二层：柱状图</h1>
      <canvas id="histogramCanvas" width="800" height="450" style="background-color: darkseagreen"></canvas>
    </div>
    <div class="canvas-svg">
      <h1>第三层：矢量图</h1>
      <svg style="width: 800px; height: 600px; background-color: green">
        <line x1="100" y1="100" x2="200" y2="200" stroke="red"></line>
        <line x1="100" y1="200" x2="200" y2="100" stroke="red"></line>
        <polyline points="300, 300, 50, 100, 120, 400, 20, 20" fill-opacity="0" stroke="cyan"></polyline>
        <rect x="400" y="400" width="150" height="50" fill="pink"></rect>
        <circle r="50" cx="370" cy="95" style="stroke: cyan; fill: none"></circle>
        <ellipse rx="100" ry="50" cx="500" cy="500" style="fill: black"></ellipse>
        <polygon points="600 100, 300 400, 750 100" stroke="red" fill-opacity="0"></polygon>
        <path d="M 10 10 L 20 400 L 30 120 L 40 66 L 50 99 L 60 120 L 70 99 Z"></path>
      </svg>
    </div>
    <h1>第四层：ECharts1</h1>
    <div class="canvas-echarts1" style="width: 800px; height: 400px; background-color: white">
    </div>
    <h1>第四层：ECharts2</h1>
    <div class="canvas-echarts2" style="width: 800px; height: 400px; background-color: white">
    </div>
    <h1>第四层：ECharts3</h1>
    <div class="canvas-echarts3" style="width: 800px; height: 400px; background-color: white">
    </div>
  </div>
</template>

<script>
export default {
  name: 'CanvasView',
  mounted() {
    /**
     * 常用方法的使用：
     * 1.getContext('2d')：获取 2D 绘图上下文。它返回一个用于在 Canvas 上进行绘图操作的上下文对象。
     *     const canvas = document.getElementById('myCanvas');
     *     const ctx = canvas.getContext('2d');
     * 2.beginPath()：开始一个新的路径。它用于定义一个路径，路径可以包含直线、曲线、弧线等。
     *     ctx.beginPath();
     * 3.closePath()：闭合路径。它将当前路径的起点和终点连接起来，形成一个闭合的图形。
     *     ctx.closePath();
     *     ctx.closePath();
     * 4.lineTo(x, y)：添加一条直线到指定的坐标点。它用于在路径中添加一个直线段。
     *     ctx.lineTo(100, 100);
     * 5.rect(x, y, width, height)：创建一个矩形路径。它用于在路径中添加一个矩形。
     *     ctx.rect(50, 50, 100, 100);
     * 6.arc(x, y, radius, startAngle, endAngle, anticlockwise)：创建一段圆弧路径。它用于在路径中添加一个圆弧。
     *     ctx.arc(100, 100, 50, 0, Math.PI * 2, false);
     * 7.moveTo(x, y)：将路径的起点移动到指定的坐标点。它用于在路径中移动当前位置，而不绘制任何线条。
     *     ctx.moveTo(50, 50);
     * 8.stroke()：绘制路径的边框。它用于根据路径的定义绘制出路径的边框。
     *     ctx.stroke();
     *
     * @type {HTMLCanvasElement}
     */
    this.clockCanvas()
    this.histogramCanvas()
    this.canvasEcharts1()
    this.canvasEcharts2()
    this.canvasEcharts3()
  },
  methods: {
    clockCanvas() {
      // 获取 Canvas 元素和 2D 上下文
      const canvas = document.getElementById('clockCanvas')
      const ctx = canvas.getContext('2d')
      // 获取 Canvas 的中心点坐标
      const centerX = canvas.width / 2
      const centerY = canvas.height / 2

      // 绘制时钟的外圆
      function drawClockFace() {
        ctx.beginPath()
        ctx.arc(centerX, centerY, 190, 0, Math.PI * 2)
        ctx.lineWidth = 5
        ctx.strokeStyle = '#000'
        ctx.stroke()
        ctx.closePath()
      }
      // 绘制时钟的刻度
      function drawClockTicks() {
        for (let i = 0; i < 12; i++) {
          const angle = Math.PI / 6 * i
          const x1 = centerX + Math.sin(angle) * 160
          const y1 = centerY - Math.cos(angle) * 160
          const x2 = centerX + Math.sin(angle) * 180
          const y2 = centerY - Math.cos(angle) * 180
          ctx.beginPath()
          ctx.moveTo(x1, y1)
          ctx.lineTo(x2, y2)
          ctx.lineWidth = 3
          ctx.strokeStyle = '#000'
          ctx.stroke()
          ctx.closePath()
        }
      }
      // 绘制时钟的指针
      function drawClockHands() {
        const now = new Date()
        const hours = now.getHours()
        const minutes = now.getMinutes()
        const seconds = now.getSeconds()
        // 绘制时针
        const hourAngle = Math.PI / 6 * (hours % 12) + Math.PI / 360 * minutes
        const hourHandLength = 100
        const hourX = centerX + Math.sin(hourAngle) * hourHandLength
        const hourY = centerY - Math.cos(hourAngle) * hourHandLength
        ctx.beginPath()
        ctx.moveTo(centerX, centerY)
        ctx.lineTo(hourX, hourY)
        ctx.lineWidth = 8
        ctx.strokeStyle = '#000'
        ctx.stroke()
        ctx.closePath()
        // 绘制分针
        const minuteAngle = Math.PI / 30 * minutes + Math.PI / 1800 * seconds
        const minuteHandLength = 140
        const minuteX = centerX + Math.sin(minuteAngle) * minuteHandLength
        const minuteY = centerY - Math.cos(minuteAngle) * minuteHandLength
        ctx.beginPath()
        ctx.moveTo(centerX, centerY)
        ctx.lineTo(minuteX, minuteY)
        ctx.lineWidth = 5
        ctx.strokeStyle = '#000'
        ctx.stroke()
        ctx.closePath()
        // 绘制秒针
        const secondAngle = Math.PI / 30 * seconds
        const secondHandLength = 160
        const secondX = centerX + Math.sin(secondAngle) * secondHandLength
        const secondY = centerY - Math.cos(secondAngle) * secondHandLength
        ctx.beginPath()
        ctx.moveTo(centerX, centerY)
        ctx.lineTo(secondX, secondY)
        ctx.lineWidth = 2
        ctx.strokeStyle = '#f00'
        ctx.stroke()
        ctx.closePath()
      }
      // 绘制整个时钟
      function drawClock() {
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        drawClockFace()
        drawClockTicks()
        drawClockHands()
        requestAnimationFrame(drawClock)
      }
      // 开始绘制时钟
      drawClock()
    },
    histogramCanvas() {
      // 获取Canvas元素
      const canvas = document.getElementById('histogramCanvas')
      // 获取Canvas元素的上下文对象（2D）
      const ctx = canvas.getContext('2d')
      // 绘制文本（左上角的文本）
      ctx.font = '16px 微软雅黑'
      ctx.fillText('数据可视化', 50, 80)
      // 绘制线段
      ctx.moveTo(100, 100)
      ctx.lineTo(100, 400)
      ctx.lineTo(700, 400)
      ctx.lineTo(700, 100)
      ctx.stroke()
      // 绘制垂直轴（Y轴）左部的线段
      ctx.moveTo(100, 100)
      ctx.lineTo(700, 100)
      ctx.moveTo(100, 160)
      ctx.lineTo(700, 160)
      ctx.moveTo(100, 220)
      ctx.lineTo(700, 220)
      ctx.moveTo(100, 280)
      ctx.lineTo(700, 280)
      ctx.moveTo(100, 340)
      ctx.lineTo(700, 340)
      ctx.fillText('150', 70, 110)
      ctx.fillText('120', 70, 170)
      ctx.fillText('090', 70, 230)
      ctx.fillText('060', 70, 290)
      ctx.fillText('030', 70, 350)
      ctx.stroke()
      // 绘制水平轴（X轴）底部的线段
      ctx.moveTo(250, 400)
      ctx.lineTo(250, 410)
      ctx.moveTo(400, 400)
      ctx.lineTo(400, 410)
      ctx.moveTo(550, 400)
      ctx.lineTo(550, 410)
      ctx.fillText('食品', 160, 420)
      ctx.fillText('数码', 300, 420)
      ctx.fillText('服饰', 460, 420)
      ctx.fillText('箱包', 600, 420)
      ctx.stroke()
      // 绘制矩形
      ctx.fillStyle = 'black'
      ctx.fillRect(140, 200, 80, 200)
      ctx.fillRect(280, 300, 80, 100)
      ctx.fillRect(440, 120, 80, 280)
      ctx.fillRect(580, 250, 80, 150)
      ctx.stroke()
      // 闭合线段
      // ctx.closePath()
    },
    canvasEcharts1() {
      const dom = document.querySelector('.canvas-echarts1')
      const myCharts = this.$echarts.init(dom)
      myCharts.setOption({
        title: {
          text: '数据可视化',
          textStyle: {
            color: 'red'
          },
          left: 'center',
          subtext: 'echarts基本的使用',
          subtextStyle: {
            color: 'black'
          }
        },
        xAxis: {
          data: ['衣服', '直播', '游戏', '电影']
        },
        yAxis: {
          axisLine: {
            show: true
          }
        },
        series: [
          {
            type: 'bar',
            data: [10, 20, 30, 40]
          }
        ]
      })
    },
    canvasEcharts2() {
      const dom = document.querySelector('.canvas-echarts2')
      const myCharts = this.$echarts.init(dom)
      myCharts.setOption({
        title: {
          text: '折线图',
          textStyle: {
            color: 'green'
          },
          left: 'center',
          subtext: 'echarts基本的使用',
          subtextStyle: {
            color: 'black'
          }
        },
        xAxis: {
          data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天']
        },
        yAxis: {
          axisLine: {
            show: true
          }
        },
        series: [
          {
            type: 'line',
            data: [15, 5, 35, 10, 55, 25, 75]
          }
        ]
      })
    },
    canvasEcharts3() {
      // 1.获取EChart画布容器DOM对象
      const dom = document.querySelector('.canvas-echarts3')
      // 2.初始化EChart画布实例对象
      const myCharts = this.$echarts.init(dom)
      // 3.配置ECharts画布数据
      myCharts.setOption({
        // 标题
        // title: {
        //   text: '画布主题',
        //   textStyle: {
        //     color: 'blue'
        //   },
        //   left: 'center',
        //   subtext: '画布版本：echarts基本的使用',
        //   subtextStyle: {
        //     color: 'gray'
        //   }
        // },
        // 横坐标：水平方向（X轴）
        xAxis: {
          type: 'category'
        },
        // 纵坐标：垂直方向（Y轴）
        yAxis: {},
        // 配置数据源
        dataset: {
          source: [
            ['Jan', 34, 20, '杰尼龟', 52],
            ['Feb', 28, 14, '石斑鱼', 54],
            ['Mar', 45, 32, '大斑马', 42],
            ['Apr', 69, 46],
            ['May', 39, 24],
            ['Jun', 43, 23],
            ['Jul', 33, 23],
            ['Aug', 23, 13],
            ['Sep', 23, 16],
            ['Oct', 33, 20],
            ['Nov', 39, 24],
            ['Dec', 22, 15]
          ]
        },
        // 串联组件
        series: [
          {
            name: '饼状图',
            type: 'pie',
            center: ['75%', 80],
            radius: 35,
            encode: { itemName: 3, value: 4 }
          },
          {
            name: '折线图',
            type: 'line',
            encode: { x: 0, y: 1 }
          },
          {
            name: '柱状图',
            type: 'bar',
            encode: { x: 0, y: 2 }
          }
        ],
        // 提示组件
        tooltip: {
          textStyle: {
            color: 'black'
          }
        },
        // 系列切换组件（配合串联组件（series）：name属性）
        legend: {
          data: ['饼状图', '折线图', '柱状图']
        },
        // 工具栏组件
        toolbox: {
          show: true,
          feature: {
            dataZoom: {
              yAxisIndex: 'none'
            },
            dataView: {
              readOnly: false
            },
            magicType: {
              type: ['line', 'bar']
            },
            restore: {},
            saveAsImage: {}
          }
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>
/**
 * div + canvas 居中:
 * 1.<div>和<canvas>是HTML5中常用的元素，用于创建页面中的图形和动画效果。
 * 2.在使用这两个元素时，一个常见的问题是如何将它们居中显示在页面中。
 * 3.本文将介绍几种常用的方法来实现<canvas>元素的居中显示。
 * 方法一：
 * 使用CSS的Flexbox布局 Flexbox是一种新的CSS布局模式，在处理页面布局时非常方便。要将<canvas>元素居中显示，只需将其包裹在一个<div>元素中，并使用CSS的Flexbox属性来设置居中对齐。以下是一个示例代码：
 * <div style="display: flex; align-items: center; justify-content: center;">
 *   <canvas></canvas>
 * </div>
 * 以上代码通过设置<div>元素的display属性为flex，然后使用align-items和justify-content属性将元素水平和垂直居中对齐。通过这个简单的设置，就可以将<canvas>元素完美居中显示。
 * 方法二：
 * 使用CSS的绝对定位和transform属性 另一种方法是使用CSS的绝对定位和transform属性来实现<canvas>元素的居中显示。以下是一个示例代码：
 * <div style="position: relative; width: 100%; height: 100%;">
 *   <canvas style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"></canvas>
 * </div>
 * 以上代码通过设置<div>元素的position属性为relative，然后将<canvas>元素的position属性设置为absolute，并使用top和left属性将其居中定位。最后，使用transform属性来向左和向上移动元素的50%，从而达到居中显示的效果。
 * 方法三：
 * 使用CSS的网格布局 CSS的网格布局提供了一种灵活的布局方式，可以轻松实现元素的居中显示。以下是一个示例代码：
 * <div style="display: grid; place-items: center; height: 100vh;">
 *   <canvas></canvas>
 * </div>
 * 以上代码通过设置<div>元素的display属性为grid，然后使用place-items属性将元素居中对齐。通过这个简单的设置，<canvas>元素将完美居中显示。
 * 注意：
 * 请问：height:100vh 和 height:100% 的区别？
 * 回答：1vh它表示的是当前屏幕可见高度的1/100，而1%它表示的是父元素长或者宽的1%。
 */
.canvas {
  &-one {
    color: red;
  }

  &-clock {
    color: blue;
  }

  &-histogram {
    color: green;
  }
}
</style>
